using System;
using System.Collections.Generic;
using abilities.effects;
using abilities.targets;
using abilities.triggers;
using LitJson;
using UnityEngine;
using UnityEngine.Assertions;

namespace abilities.templates
{
    //效果模板，即配表。从json中提取
    public class EffectTemplate
    {
        static Dictionary<int, EffectTemplate> idToTemplate = new();
        public AbilityEffectStackType stackType;

        public int Id { get; private set; }
        public float castTime  { get; private set; }
        public float totalTime  { get; private set; }
        //冷却时间。
        public float cooldown  { get; private set; }
        public bool interruptAttack  { get; private set; }
        //开始时声音
        public string startSfx  { get; private set; }
        //移除时声音
        public string endSfx  { get; private set; }
        //是否在地面上播放特效
        public bool VfsOnGround  { get; private set; }
        // 触发器被取消 例如死亡
        public bool cancelTriggering  { get; private set; }

        public AnimationRule animationRule { get; private set; }
        //目标和范围，一个点一个范围——一个圆。
        public Target target  { get; private set; }
        public AbilityTriggerTemplate startTrigger  { get; private set; }
        public AbilityTriggerTemplate endTrigger  { get; private set; }
        //开始时特效
        public List<string> startVfx  { get; private set; }
        //移除时特效
        public List<string> endVfx  { get; private set; }
        //震动
        public float shake  { get; private set; }
        
        public static EffectTemplate getById(int id)
        {
            if (!idToTemplate.TryGetValue(id, out var iter))
            {
                Debug.LogError("getById not found");
                return null;
            }

            return iter;
        }

        protected EffectTemplate()
        {            
            stackType = AbilityEffectStackType.Stackable;
            startVfx = new List<string>();
            endVfx = new List<string>();
        }

        public virtual Effect CreateInstance(int level)
        {
            return null;
        }

        public static EffectTemplate ParseJson(LitJson.JsonData value)
        {
            EffectTemplate result = null;
            if (value.GetJsonType() == JsonType.None)
                return result;

            string type = (string)value["type"];
            if ("ParameterModifier" == type)
            {
                result = new EffectParameterModifierTemplate();
            }
            else if ("SpawnEffects" == type)
            {
                result = new EffectSpawnEffectsTemplate();
            }
            else if ("EffectLimits" == type)
            {
                result = new EffectLimitsTemplate();
            }
            else if ("HitData" == type)
            {
                result = new EffectHitDataTemplate();
            }
            else if ("WalkThroughWalls" == type)
            {
                result = new EffectWalkThroughWallsTemplate();
            }
            else if ("Immune" == type)
            {
                result = new EffectImmuneTemplate();
            }
            else
            {
                Debug.Log("Wrong ability type");
            }

            if (result != null)
            {
                result.FromJson(value);
            }

            return result;
        }


        public virtual bool FromJson(LitJson.JsonData value)
        {
            if (value.ContainsKey("Id"))
            {
                Id = (int)value["Id"];
                if (idToTemplate.ContainsKey(Id))
                {
                    Debug.LogError("fromJson duplicate Id : "+Id);
                }

                idToTemplate.Add(Id, this);
            }
            else
            {
                Debug.LogError("fromJson no Id specified");
            }

            Assert.IsTrue(Id < 255, "AbilityEffectTemplate has id more than 255");

            castTime = (int)value["castTime"]*0.001f;
            totalTime = (int)value["totalTime"]*0.001f;
            cooldown = (int)value["cooldown"]*0.001f;
            interruptAttack = (bool)value["interruptAttack"];
            startSfx = (string)value["startSfx"];
            endSfx = (string)value["endSfx"];
            VfsOnGround = (bool)value["VfsOnGround"];
            cancelTriggering = (bool)value["cancelTriggering"];

            target = Target.TargetFromJson(value["target"]);
            startTrigger = AbilityTriggerTemplate.TriggerFromJson(value["startTrigger"], true);
            endTrigger = AbilityTriggerTemplate.TriggerFromJson(value["endTrigger"], false);

            FromJsonAnimation(value.ContainsKey("animation")?value["animation"]:null);

            if (value.ContainsKey("stackType"))
                stackType = Enum.Parse<AbilityEffectStackType>((string)value["stackType"]);

            if (value.ContainsKey("startVfx"))
            {
                foreach (var i in value["startVfx"])
                {
                    startVfx.Add((string)i);
                }
            }

            if (value.ContainsKey("endVfx"))
            {
                foreach (var i in value["endVfx"])
                {
                    endVfx.Add((string)i);
                }
            }

            shake = (int)value["shake"] / 100.0f;
            return true;
        }



        private void FromJsonAnimation(LitJson.JsonData value)
        {
            if (value == null)
            {
                animationRule = null;
                return;
            }
            animationRule = new AnimationRule();
            animationRule.FromJsonAnimation(value);
        }


        public static void FromJsonToArray(JsonData value, List<int> destination)
        {
            if (value == null || (destination == null))
                return;
            foreach (JsonData i in value)
            {
                destination.Add((int)i);
            }
        }

        public static int GetByLevel(List<int> source, int level)
        {
            if (source == null || source.Count < 1 || level < 1)
            {
                return 0;
            }

            if ((int) source.Count < level)
            {
                return source[source.Count - 1];
            }
            else
            {
                return source[level - 1];
            }
        }
    }
}